package redis

import (
	"fmt"
	"time"

	"github.com/go-redis/redis"
)

type RedisConfig struct {
	Host      string `yaml:"host" mapstructure:"host"`
	Port      int    `yaml:"port" mapstructure:"port"`
	Password  string `yaml:"password" mapstructure:"password"`
	Db        int    `yaml:"db" mapstructure:"db"`
	PoolSize  int    `yaml:"pool_size" mapstructure:"pool_size"`
	IdleConns int    `yaml:"idle_conns" mapstructure:"idle_conns"`
}

type RedisClient struct {
	client *redis.Client
}

func NewRedisClient(config RedisConfig) *RedisClient {
	rd := &RedisClient{}
	addr := fmt.Sprintf("%s:%d", config.Host, config.Port)
	options := &redis.Options{
		Network: "tcp",
		Addr:    addr,
		// Password: config.Password,
		DB: config.Db,
		// PoolSize:     config.PoolSize,
		// MinIdleConns: config.IdleConns,
	}
	if config.Password != "" {
		options.Password = config.Password
	}
	rd.client = redis.NewClient(options)
	_, err := rd.client.Ping().Result()
	if err != nil {
		panic(err)
	}

	return rd
}

func (rd *RedisClient) String(key string) (string, error) {
	return rd.client.Get(key).Result()
}

func (rd *RedisClient) Get(key string, value interface{}) error {
	// str, err := rd.String(key)
	// if err != nil {
	// 	return err
	// }
	// err = value.(encoding.BinaryUnmarshaler).UnmarshalBinary([]byte(str))
	// return err
	return rd.client.Get(key).Scan(value)
}

func (rd *RedisClient) Int(key string) (int, error) {
	return rd.client.Get(key).Int()
}
func (rd *RedisClient) Int64(key string) (int64, error) {
	return rd.client.Get(key).Int64()
}

func (rd *RedisClient) HGetAll(key string) (map[string]string, error) {
	return rd.client.HGetAll(key).Result()
}

func (rd *RedisClient) HString(key, field string) (
	string, error) {
	return rd.client.HGet(key, field).Result()
}

func (rd *RedisClient) HInt(key, field string) (int, error) {
	return rd.client.HGet(key, field).Int()
}

func (rd *RedisClient) Set(key string, value interface{},
	expired int) error {
	return rd.client.Set(key, value,
		time.Duration(expired)*time.Second).Err()
}

func (rd *RedisClient) Del(key string) error {
	return rd.client.Del(key).Err()
}

func (rd *RedisClient) HSet(key, field string, value interface{}) error {
	err := rd.client.HSet(key, field, value).Err()
	if err != nil {
		return err
	}
	rd.client.Expire(key, time.Hour*30*24)
	return rd.client.HSet(key, field, value).Err()
}
func (rd *RedisClient) HDelete(key, field string) error {
	return rd.client.HDel(key, field).Err()
}

func (rd *RedisClient) SMembers(key string) ([]string, error) {
	return rd.client.SMembers(key).Result()
}

func (rd *RedisClient) Incr(key string, factor int64) (int64, error) {
	return rd.client.IncrBy(key, factor).Result()
}

func (rd *RedisClient) Expire(key string, expired int) (bool, error) {
	return rd.client.Expire(key, time.Duration(expired)*time.Second).Result()
}

func (rd *RedisClient) Exist(key string) (bool, error) {
	if cnt, err := rd.client.Exists(key).Result(); err != nil {
		return false, err
	} else {
		return cnt > 0, nil
	}
}

func (rd *RedisClient) ExecuteScript(script string, keys []string, args ...string) (interface{}, error) {
	return rd.client.Eval(script, keys, args).Result()
}

func (rd *RedisClient) Close() {
	rd.client.Close()
}

func (rd *RedisClient) Connection() *redis.Client {
	return rd.client
}

func (rd *RedisClient) Keys(prefix string) ([]string, error) {
	return rd.client.Keys(prefix).Result()
}

func (rd *RedisClient) DelMultiple(key []string) error {
	return rd.client.Del(key...).Err()
}
